﻿#include "stdafx.h"
#if _QG_USE_GL
#include "qg/qgasv.h"
#include "qg_ogl_dev.h"
#include "qg_ogl_dev_ext.h"
#include "qg_trace.h"

namespace _ogl
{
	// GL 전용 능력치
	bool GLCS[QGLX_MAX_VALUE];

	// 텍스쳐
	PFNGLACTIVETEXTUREARBPROC pglActiveTextureARB;
	PFNGLCLIENTACTIVETEXTUREARBPROC pglClientActiveTextureARB;
	PFNGLCOMPRESSEDTEXIMAGE2DPROC pglCompressedTexImage2D;
	PFNGLGENERATEMIPMAPPROC pglGenerateMipmap;
	PFNGLGENERATEMIPMAPEXTPROC pglGenerateMipmapEXT;
	// 블렌드
	PFNGLBLENDEQUATIONPROC pglBlendEquation;
	PFNGLBLENDEQUATIONEXTPROC pglBlendEquationEXT;
	PFNGLBLENDFUNCSEPARATEPROC pglBlendFuncSeparate;
	PFNGLBLENDFUNCSEPARATEEXTPROC pglBlendFuncSeparateEXT;
	PFNGLENABLEINDEXEDEXTPROC pglEnableIndexedEXT;
	PFNGLDISABLEINDEXEDEXTPROC pglDisableIndexedEXT;
	PFNGLCOLORMASKINDEXEDEXTPROC pglColorMaskIndexedEXT;
	PFNGLBLENDFUNCIPROC pglBlendFunciARB;
	PFNGLBLENDFUNCINDEXEDAMDPROC pglBlendFuncIndexedAMD;
	PFNGLBLENDEQUATIONIPROC pglBlendEquationiARB;
	PFNGLBLENDEQUATIONINDEXEDAMDPROC pglBlendEquationIndexedAMD;
	// 레이아웃	
	PFNGLENABLEVERTEXATTRIBARRAYPROC pglEnableVertexAttribArray;
	PFNGLDISABLEVERTEXATTRIBARRAYPROC pglDisableVertexAttribArray;
	PFNGLSECONDARYCOLORPOINTERPROC pglSecondaryColorPointer;
	PFNGLVERTEXATTRIBPOINTERPROC pglVertexAttribPointer;
	// FBO
	PFNGLGENFRAMEBUFFERSPROC pglGenFramebuffers;
	PFNGLBINDFRAMEBUFFERPROC pglBindFramebuffer;
	PFNGLDELETEFRAMEBUFFERSPROC pglDeleteFramebuffers;
	PFNGLCHECKFRAMEBUFFERSTATUSPROC pglCheckFramebufferStatus;
	PFNGLFRAMEBUFFERTEXTURE1DPROC pglFramebufferTexture1D;
	PFNGLFRAMEBUFFERTEXTURE2DPROC pglFramebufferTexture2D;
	PFNGLFRAMEBUFFERTEXTURE3DPROC pglFramebufferTexture3D;
	PFNGLGENRENDERBUFFERSPROC pglGenRenderbuffers;
	PFNGLBINDRENDERBUFFERPROC pglBindRenderbuffer;
	PFNGLDELETERENDERBUFFERSPROC pglDeleteRenderbuffers;
	PFNGLRENDERBUFFERSTORAGEPROC pglRenderbufferStorage;
	PFNGLFRAMEBUFFERRENDERBUFFERPROC pglFramebufferRenderbuffer;
	PFNGLGETRENDERBUFFERPARAMETERIVPROC pglGetRenderbufferParameteriv;
	PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC pglGetFramebufferAttachmentParameteriv;
	PFNGLGENFRAMEBUFFERSEXTPROC pglGenFramebuffersEXT;
	PFNGLBINDFRAMEBUFFEREXTPROC pglBindFramebufferEXT;
	PFNGLDELETEFRAMEBUFFERSEXTPROC pglDeleteFramebuffersEXT;
	PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC pglCheckFramebufferStatusEXT;
	PFNGLFRAMEBUFFERTEXTURE1DEXTPROC pglFramebufferTexture1DEXT;
	PFNGLFRAMEBUFFERTEXTURE2DEXTPROC pglFramebufferTexture2DEXT;
	PFNGLFRAMEBUFFERTEXTURE3DEXTPROC pglFramebufferTexture3DEXT;
	PFNGLGENRENDERBUFFERSEXTPROC pglGenRenderbuffersEXT;
	PFNGLBINDRENDERBUFFEREXTPROC pglBindRenderbufferEXT;
	PFNGLDELETERENDERBUFFERSEXTPROC pglDeleteRenderbuffersEXT;
	PFNGLRENDERBUFFERSTORAGEEXTPROC pglRenderbufferStorageEXT;
	PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC pglFramebufferRenderbufferEXT;
	PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC pglGetRenderbufferParameterivEXT;
	PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC pglGetFramebufferAttachmentParameterivEXT;
	// 프로그램과 세이더
	PFNGLCREATEPROGRAMPROC pglCreateProgram;
	PFNGLDELETEPROGRAMPROC pglDeleteProgram;
	PFNGLATTACHSHADERPROC pglAttachShader;
	PFNGLDETACHSHADERPROC pglDetachShader;
	PFNGLGETATTACHEDSHADERSPROC pglGetAttachedShaders;
	PFNGLGETSHADERIVPROC pglGetProgramiv;
	PFNGLGETPROGRAMINFOLOGPROC pglGetProgramInfoLog;
	PFNGLGETACTIVEATTRIBPROC pglGetActiveAttrib;
	PFNGLGETACTIVEUNIFORMPROC pglGetActiveUniform;
	PFNGLGETATTRIBLOCATIONPROC pglGetAttribLocation;
	PFNGLGETUNIFORMLOCATIONPROC pglGetUniformLocation;
	PFNGLCREATESHADERPROC pglCreateShader;
	PFNGLSHADERSOURCEPROC pglShaderSource;
	PFNGLCOMPILESHADERPROC pglCompileShader;
	PFNGLLINKPROGRAMPROC pglLinkProgram;
	PFNGLUSEPROGRAMPROC pglUseProgram;
	PFNGLDELETESHADERPROC pglDeleteShader;
	PFNGLGETSHADERIVPROC pglGetShaderiv;
	PFNGLGETSHADERINFOLOGPROC pglGetShaderInfoLog;
	PFNGLUNIFORM1FVARBPROC pglUniform1fvARB;
	PFNGLUNIFORM2FVARBPROC pglUniform2fvARB;
	PFNGLUNIFORM3FVARBPROC pglUniform3fvARB;
	PFNGLUNIFORM4FVARBPROC pglUniform4fvARB;
	PFNGLUNIFORM1IVARBPROC pglUniform1ivARB;
	PFNGLUNIFORM2IVARBPROC pglUniform2ivARB;
	PFNGLUNIFORM3IVARBPROC pglUniform3ivARB;
	PFNGLUNIFORM4IVARBPROC pglUniform4ivARB;
	PFNGLUNIFORMMATRIX2FVARBPROC pglUniformMatrix2fvARB;
	PFNGLUNIFORMMATRIX3FVARBPROC pglUniformMatrix3fvARB;
	PFNGLUNIFORMMATRIX4FVARBPROC pglUniformMatrix4fvARB;
	PFNGLPROGRAMPARAMETERIARBPROC pglProgramParameteriARB;
	PFNGLPROGRAMPARAMETERIEXTPROC pglProgramParameteriEXT;
	// 버퍼
	PFNGLGENBUFFERSARBPROC pglGenBuffersARB;
	PFNGLBINDBUFFERARBPROC pglBindBufferARB;
	PFNGLDELETEBUFFERSARBPROC pglDeleteBuffersARB;
	PFNGLBUFFERDATAARBPROC pglBufferDataARB;
	PFNGLBUFFERSUBDATAARBPROC pglBufferSubDataARB;
	PFNGLGETBUFFERSUBDATAARBPROC pglGetBufferSubDataARB;
	PFNGLMAPBUFFERARBPROC pglMapBufferARB;
	PFNGLUNMAPBUFFERARBPROC pglUnmapBufferARB;
	PFNGLISBUFFERARBPROC pglIsBufferARB;
	PFNGLDRAWBUFFERSPROC pglDrawBuffers;
	PFNGLDRAWBUFFERSARBPROC pglDrawBuffersARB;
	PFNGLDRAWBUFFERSATIPROC pglDrawBuffersATI;
	PFNGLPROVOKINGVERTEXPROC pglProvokingVertexARB;
	PFNGLPROVOKINGVERTEXEXTPROC pglProvokingVertexEXT;
	// 포인트
	PFNGLPOINTPARAMETERFARBPROC  pglPointParameterfARB;
	PFNGLPOINTPARAMETERFVARBPROC pglPointParameterfvARB;
	// 스텐실
	PFNGLSTENCILFUNCSEPARATEPROC pglStencilFuncSeparate;
	PFNGLSTENCILFUNCSEPARATEATIPROC pglStencilFuncSeparateATI;
	PFNGLSTENCILOPSEPARATEPROC pglStencilOpSeparate;
	PFNGLSTENCILOPSEPARATEATIPROC pglStencilOpSeparateATI;
	PFNGLACTIVESTENCILFACEEXTPROC pglActiveStencilFaceEXT;
	// 오클루전
	PFNGLGENQUERIESARBPROC pglGenQueriesARB;
	PFNGLDELETEQUERIESARBPROC pglDeleteQueriesARB;
	PFNGLISQUERYARBPROC pglIsQueryARB;
	PFNGLBEGINQUERYARBPROC pglBeginQueryARB;
	PFNGLENDQUERYARBPROC pglEndQueryARB;
	PFNGLGETQUERYIVARBPROC pglGetQueryivARB;
	PFNGLGETQUERYOBJECTIVARBPROC pglGetQueryObjectivARB;
	PFNGLGETQUERYOBJECTUIVARBPROC pglGetQueryObjectuivARB;
	PFNGLGENOCCLUSIONQUERIESNVPROC pglGenOcclusionQueriesNV;
	PFNGLDELETEOCCLUSIONQUERIESNVPROC pglDeleteOcclusionQueriesNV;
	PFNGLISOCCLUSIONQUERYNVPROC pglIsOcclusionQueryNV;
	PFNGLBEGINOCCLUSIONQUERYNVPROC pglBeginOcclusionQueryNV;
	PFNGLENDOCCLUSIONQUERYNVPROC pglEndOcclusionQueryNV;
	PFNGLGETOCCLUSIONQUERYIVNVPROC pglGetOcclusionQueryivNV;
	PFNGLGETOCCLUSIONQUERYUIVNVPROC pglGetOcclusionQueryuivNV;
	// 기타
#if defined(WGL_EXT_swap_control)
	PFNWGLSWAPINTERVALEXTPROC pwglSwapIntervalEXT;
#endif
#if defined(GLX_SGI_swap_control)
	PFNGLXSWAPINTERVALSGIPROC pglxSwapIntervalSGI;
#endif
#if defined(GLX_EXT_swap_control)
	PFNGLXSWAPINTERVALEXTPROC pglxSwapIntervalEXT;
#endif
#if defined(GLX_MESA_swap_control)
	PFNGLXSWAPINTERVALMESAPROC pglxSwapIntervalMESA;
#endif

	// 텍스쳐
	void QglActiveTexture(GLenum texture)
	{
		if (pglActiveTextureARB)
			pglActiveTextureARB(texture);
	}

	void QglClientActiveTexture(GLenum texture)
	{
		if (pglClientActiveTextureARB)
			pglClientActiveTextureARB(texture);
	}

	void QglCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data)
	{
		if (pglCompressedTexImage2D)
			pglCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
	}

	void QglGenerateMipmap(GLenum target)
	{
		if (pglGenerateMipmap)
			pglGenerateMipmap(target);
		else if (pglGenerateMipmapEXT)
			pglGenerateMipmapEXT(target);
	}

	// 블렌드
	void QglBlendEquation(GLenum mode)
	{
		if (pglBlendEquation)
			pglBlendEquation(mode);
		else if (pglBlendEquationEXT)
			pglBlendEquationEXT(mode);
	}

	void QglBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha)
	{
		if (pglBlendFuncSeparate)
			pglBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
		else if (pglBlendFuncSeparateEXT)
			pglBlendFuncSeparateEXT(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
		else
		{
			// 어쩔수 없이 RGB만
			glBlendFunc(sfactorRGB, dfactorRGB);
		}
	}

	void QglEnableIndexed(GLenum target, GLuint index)
	{
		if (GLCS[QGLX_EXT_DRAW_BUFFERS_2] && pglEnableIndexedEXT)
			pglEnableIndexedEXT(target, index);
	}

	void QglDisableIndexed(GLenum target, GLuint index)
	{
		if (GLCS[QGLX_EXT_DRAW_BUFFERS_2] && pglDisableIndexedEXT)
			pglDisableIndexedEXT(target, index);
	}

	void QglColorMaskIndexed(GLuint buf, GLboolean r, GLboolean g, GLboolean b, GLboolean a)
	{
		if (GLCS[QGLX_EXT_DRAW_BUFFERS_2] && pglColorMaskIndexedEXT)
			pglColorMaskIndexedEXT(buf, r, g, b, a);
	}

	void QglBlendFuncIndexed(GLuint buf, GLenum src, GLenum dst)
	{
		if (GLCS[QGLX_ARB_DRAW_BUFFERS_BLEND] && pglBlendFunciARB)
			pglBlendFunciARB(buf, src, dst);
		else if (GLCS[QGLX_AMD_DRAW_BUFFERS_BLEND] && pglBlendFuncIndexedAMD)
			pglBlendFuncIndexedAMD(buf, src, dst);
	}

	void QglBlendEquationIndexed(GLuint buf, GLenum mode)
	{
		if (GLCS[QGLX_ARB_DRAW_BUFFERS_BLEND] && pglBlendEquationiARB)
			pglBlendEquationiARB(buf, mode);
		else if (GLCS[QGLX_AMD_DRAW_BUFFERS_BLEND] && pglBlendEquationIndexedAMD)
			pglBlendEquationIndexedAMD(buf, mode);
	}

	// 레이아웃	
	void QglEnableVertexArray(GLuint index)
	{
		if (pglEnableVertexAttribArray)
			pglEnableVertexAttribArray(index);
	}

	void QglDisableVertexArray(GLuint index)
	{
		if (pglDisableVertexAttribArray)
			pglDisableVertexAttribArray(index);
	}

	void QglSecondaryColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid* pointer)
	{
		if (pglSecondaryColorPointer)
			pglSecondaryColorPointer(size, type, stride, pointer);
	}

	void QglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer)
	{
		if (pglVertexAttribPointer)
			pglVertexAttribPointer(index, size, type, normalized, stride, pointer);
	}

	// FBO
	void QglGenFramebuffers(GLsizei n, GLuint* framebuffers)
	{
		if (framebuffers)
			memset(framebuffers, 0, n * sizeof(GLuint));

		if (pglGenFramebuffers)
			pglGenFramebuffers(n, framebuffers);
		else if (pglGenFramebuffersEXT)
			pglGenFramebuffersEXT(n, framebuffers);
	}

	void QglBindFramebuffer(GLenum target, GLuint framebuffer)
	{
		if (pglBindFramebuffer)
			pglBindFramebuffer(target, framebuffer);
		else if (pglBindFramebufferEXT)
			pglBindFramebufferEXT(target, framebuffer);
	}

	void QglDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
	{
		if (pglDeleteFramebuffers)
			pglDeleteFramebuffers(n, framebuffers);
		else if (pglDeleteFramebuffersEXT)
			pglDeleteFramebuffersEXT(n, framebuffers);
	}

	GLenum QglCheckFramebufferStatus(GLenum target)
	{
		if (pglCheckFramebufferStatus)
			return pglCheckFramebufferStatus(target);
		else if (pglCheckFramebufferStatusEXT)
			return pglCheckFramebufferStatusEXT(target);
		else
			return 0;
	}

	void QglFramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
	{
		if (pglFramebufferTexture1D)
			pglFramebufferTexture1D(target, attachment, textarget, texture, level);
		else if (pglFramebufferTexture1DEXT)
			pglFramebufferTexture1DEXT(target, attachment, textarget, texture, level);
	}

	void QglFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
	{
		if (pglFramebufferTexture2D)
			pglFramebufferTexture2D(target, attachment, textarget, texture, level);
		else if (pglFramebufferTexture2DEXT)
			pglFramebufferTexture2DEXT(target, attachment, textarget, texture, level);
	}

	void QglFramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
	{
		if (pglFramebufferTexture3D)
			pglFramebufferTexture3D(target, attachment, textarget, texture, level, zoffset);
		else if (pglFramebufferTexture3DEXT)
			pglFramebufferTexture3DEXT(target, attachment, textarget, texture, level, zoffset);
	}

	void QglGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
	{
		if (renderbuffers)
			memset(renderbuffers, 0, n * sizeof(GLuint));

		if (pglGenRenderbuffers)
			pglGenRenderbuffers(n, renderbuffers);
		else if (pglGenRenderbuffersEXT)
			pglGenRenderbuffersEXT(n, renderbuffers);
	}

	void QglBindRenderbuffer(GLenum target, GLuint renderbuffer)
	{
		if (pglBindRenderbuffer)
			pglBindRenderbuffer(target, renderbuffer);
		else if (pglBindRenderbufferEXT)
			pglBindRenderbufferEXT(target, renderbuffer);
	}

	void QglDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
	{
		if (pglDeleteRenderbuffers)
			pglDeleteRenderbuffers(n, renderbuffers);
		else if (pglDeleteRenderbuffersEXT)
			pglDeleteRenderbuffersEXT(n, renderbuffers);
	}

	void QglRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
	{
		if (pglRenderbufferStorage)
			pglRenderbufferStorage(target, internalformat, width, height);
		else if (pglRenderbufferStorageEXT)
			pglRenderbufferStorageEXT(target, internalformat, width, height);
	}

	void QglFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
	{
		if (pglFramebufferRenderbuffer)
			pglFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
		else if (pglFramebufferRenderbufferEXT)
			pglFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, renderbuffer);
	}

	void QglGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
	{
		if (pglGetRenderbufferParameteriv)
			pglGetRenderbufferParameteriv(target, pname, params);
		else if (pglGetRenderbufferParameterivEXT)
			pglGetRenderbufferParameterivEXT(target, pname, params);
	}

	void QglGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
	{
		if (pglGetFramebufferAttachmentParameteriv)
			pglGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
		else if (pglGetFramebufferAttachmentParameterivEXT)
			pglGetFramebufferAttachmentParameterivEXT(target, attachment, pname, params);
	}

	// 프로그램과 세이더 -> 2.0
	GLuint QglCreateProgram(void)
	{
		if (pglCreateProgram)
			return pglCreateProgram();

		return 0;
	}

	void QglDeleteProgram(GLuint object)
	{
		if (pglDeleteProgram)
			pglDeleteProgram(object);
	}

	void QglAttachShader(GLuint program, GLuint shader)
	{
		if (pglAttachShader)
			pglAttachShader(program, shader);
	}

	void QglDetachShader(GLuint program, GLuint shader)
	{
		if (pglDetachShader)
			pglDetachShader(program, shader);
	}

	void QglGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
	{
		if (count)
			*count = 0;

		if (pglGetAttachedShaders)
			pglGetAttachedShaders(program, maxcount, count, shaders);
	}

	void QglGetProgramiv(GLuint program, GLenum type, GLint* param)
	{
		if (pglGetProgramiv)
			pglGetProgramiv(program, type, param);
	}

	void QglGetProgramInfoLog(GLuint program, GLsizei maxLength, GLsizei* length, GLchar* infoLog)
	{
		if (length)
			*length = 0;

		if (pglGetProgramInfoLog)
			pglGetProgramInfoLog(program, maxLength, length, infoLog);
	}

	void QglGetActiveAttrib(GLuint program, GLuint index, GLsizei maxlength, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
	{
		if (length)
			*length = 0;

		if (pglGetActiveAttrib)
			pglGetActiveAttrib(program, index, maxlength, length, size, type, name);
	}

	void QglGetActiveUniform(GLuint program, GLuint index, GLsizei maxlength, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
	{
		if (length)
			*length = 0;

		if (pglGetActiveUniform)
			pglGetActiveUniform(program, index, maxlength, length, size, type, name);
	}

	GLint QglGetAttribLocation(GLuint program, const GLchar *name)
	{
		if (pglGetAttribLocation)
			return pglGetAttribLocation(program, name);

		return 0;
	}

	GLint QglGetUniformLocation(GLuint program, const GLchar* name)
	{
		if (pglGetUniformLocation)
			return pglGetUniformLocation(program, name);

		return 0;
	}

	GLuint QglCreateShader(GLenum shaderType)
	{
		if (pglCreateShader)
			return pglCreateShader(shaderType);

		return 0;
	}

	void QglShaderSource(GLuint shader, GLsizei numOfStrings, const char** strings, const GLint* lenOfStrings)
	{
		if (pglShaderSource)
			pglShaderSource(shader, numOfStrings, strings, lenOfStrings);
	}

	void QglCompileShader(GLuint shader)
	{
		if (pglCompileShader)
			pglCompileShader(shader);
	}

	void QglLinkProgram(GLuint program)
	{
		if (pglLinkProgram)
			pglLinkProgram(program);
	}

	void QglUseProgram(GLuint prog)
	{
		if (pglUseProgram)
			pglUseProgram(prog);
	}

	void QglDeleteShader(GLuint shader)
	{
		if (pglDeleteShader)
			pglDeleteShader(shader);
	}

	void QglGetShaderiv(GLuint shader, GLenum type, GLint* param)
	{
		if (pglGetShaderiv)
			pglGetShaderiv(shader, type, param);
		else
			*param = 0;
	}

	void QglGetShaderInfoLog(GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog)
	{
		if (length)
			*length = 0;

		if (pglGetShaderInfoLog)
			pglGetShaderInfoLog(shader, maxLength, length, infoLog);
	}

	void QglUniform1fv(GLint loc, GLsizei count, const GLfloat* v)
	{
		if (pglUniform1fvARB)
			pglUniform1fvARB(loc, count, v);
	}

	void QglUniform2fv(GLint loc, GLsizei count, const GLfloat* v)
	{
		if (pglUniform2fvARB)
			pglUniform2fvARB(loc, count, v);
	}

	void QglUniform3fv(GLint loc, GLsizei count, const GLfloat* v)
	{
		if (pglUniform3fvARB)
			pglUniform3fvARB(loc, count, v);
	}

	void QglUniform4fv(GLint loc, GLsizei count, const GLfloat* v)
	{
		if (pglUniform4fvARB)
			pglUniform4fvARB(loc, count, v);
	}

	void QglUniform1iv(GLint loc, GLsizei count, const GLint* v)
	{
		if (pglUniform1ivARB)
			pglUniform1ivARB(loc, count, v);
	}

	void QglUniform2iv(GLint loc, GLsizei count, const GLint* v)
	{
		if (pglUniform2ivARB)
			pglUniform2ivARB(loc, count, v);
	}

	void QglUniform3iv(GLint loc, GLsizei count, const GLint* v)
	{
		if (pglUniform3ivARB)
			pglUniform3ivARB(loc, count, v);
	}

	void QglUniform4iv(GLint loc, GLsizei count, const GLint* v)
	{
		if (pglUniform4ivARB)
			pglUniform4ivARB(loc, count, v);
	}

	void QglUniformMatrix2fv(GLint loc, GLsizei count, GLboolean transpose, const GLfloat* v)
	{
		if (pglUniformMatrix2fvARB)
			pglUniformMatrix2fvARB(loc, count, transpose, v);
	}

	void QglUniformMatrix3fv(GLint loc, GLsizei count, GLboolean transpose, const GLfloat* v)
	{
		if (pglUniformMatrix3fvARB)
			pglUniformMatrix3fvARB(loc, count, transpose, v);
	}

	void QglUniformMatrix4fv(GLint loc, GLsizei count, GLboolean transpose, const GLfloat* v)
	{
		if (pglUniformMatrix4fvARB)
			pglUniformMatrix4fvARB(loc, count, transpose, v);
	}

	void QglProgramParameteri(GLhandleARB program, GLenum pname, GLint value)
	{
		if (pglProgramParameteriARB)
			pglProgramParameteriARB(program, pname, value);
		else if (pglProgramParameteriEXT)
			pglProgramParameteriEXT(program, pname, value);
	}

	// 버퍼 -> 1.5
	void QglGenBuffers(GLsizei n, GLuint* buffers)
	{
		if (buffers)
			memset(buffers, 0, n * sizeof(GLuint));

		if (pglGenBuffersARB)
			pglGenBuffersARB(n, buffers);
	}

	void QglBindBuffer(GLenum target, GLuint buffer)
	{
		if (pglBindBufferARB)
			pglBindBufferARB(target, buffer);
	}

	void QglDeleteBuffers(GLsizei n, const GLuint* buffers)
	{
		if (pglDeleteBuffersARB)
			pglDeleteBuffersARB(n, buffers);
	}

	void QglBufferData(GLenum target, GLsizeiptrARB size, const GLvoid* data, GLenum usage)
	{
		if (pglBufferDataARB)
			pglBufferDataARB(target, size, data, usage);
	}

	void QglBufferSubData(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid* data)
	{
		if (pglBufferSubDataARB)
			pglBufferSubDataARB(target, offset, size, data);
	}

	void QglGetBufferSubData(GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid* data)
	{
		if (pglGetBufferSubDataARB)
			pglGetBufferSubDataARB(target, offset, size, data);
	}

	void* QglMapBuffer(GLenum target, GLenum access)
	{
		if (pglMapBufferARB)
			return pglMapBufferARB(target, access);

		return 0;
	}

	GLboolean QglUnmapBuffer(GLenum target)
	{
		if (pglUnmapBufferARB)
			return pglUnmapBufferARB(target);

		return GL_FALSE;
	}

	GLboolean QglIsBuffer(GLuint buffer)
	{
		if (pglIsBufferARB)
			return pglIsBufferARB(buffer);

		return GL_FALSE;
	}

	void QglDrawBuffers(GLsizei n, const GLenum* bufs)
	{
		if (pglDrawBuffers)
			pglDrawBuffers(n, bufs);
		else if (pglDrawBuffersARB)
			pglDrawBuffersARB(n, bufs);
		else if (pglDrawBuffersATI)
			pglDrawBuffersATI(n, bufs);
	}

	void QglProvokingVertex(GLenum mode)
	{
		if (GLCS[QGLX_ARB_PROVOKING_VERTEX] && pglProvokingVertexARB)
			pglProvokingVertexARB(mode);
		else if (GLCS[QGLX_EXT_PROVOKING_VERTEX] && pglProvokingVertexEXT)
			pglProvokingVertexEXT(mode);
	}

	// 포인트 -> 1.4
	void QglPointParameterf(GLint loc, GLfloat f)
	{
		if (pglPointParameterfARB)
			pglPointParameterfARB(loc, f);
	}

	void QglPointParameterfv(GLint loc, const GLfloat* v)
	{
		if (pglPointParameterfvARB)
			pglPointParameterfvARB(loc, v);
	}

	// 스텐실 -> 2.0
	void QglStencilFuncSeparate(GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask)
	{
		if (pglStencilFuncSeparate)
			pglStencilFuncSeparate(frontfunc, backfunc, ref, mask);
		else if (pglStencilFuncSeparateATI)
			pglStencilFuncSeparateATI(frontfunc, backfunc, ref, mask);
	}

	void QglStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
	{
		if (pglStencilOpSeparate)
			pglStencilOpSeparate(face, fail, zfail, zpass);
		else if (pglStencilOpSeparateATI)
			pglStencilOpSeparateATI(face, fail, zfail, zpass);
	}

	void QglActiveStencilFace(GLenum face)
	{
		if (pglActiveStencilFaceEXT)
			pglActiveStencilFaceEXT(face);
	}

	// 오클루전 -> 1.5
	void QglGenQueries(GLsizei n, GLuint* ids)
	{
		if (pglGenQueriesARB)
			pglGenQueriesARB(n, ids);
		else if (pglGenOcclusionQueriesNV)
			pglGenOcclusionQueriesNV(n, ids);
	}

	void QglDeleteQueries(GLsizei n, const GLuint* ids)
	{
		if (pglDeleteQueriesARB)
			pglDeleteQueriesARB(n, ids);
		else if (pglDeleteOcclusionQueriesNV)
			pglDeleteOcclusionQueriesNV(n, ids);
	}

	GLboolean QglIsQuery(GLuint id)
	{
		if (pglIsQueryARB)
			return pglIsQueryARB(id);
		else if (pglIsOcclusionQueryNV)
			return pglIsOcclusionQueryNV(id);

		return GL_FALSE;
	}

	void QglBeginQuery(GLenum target, GLuint id)
	{
		if (pglBeginQueryARB)
			pglBeginQueryARB(target, id);
		else if (pglBeginOcclusionQueryNV)
			pglBeginOcclusionQueryNV(id);
	}

	void QglEndQuery(GLenum target)
	{
		if (pglEndQueryARB)
			pglEndQueryARB(target);
		else if (pglEndOcclusionQueryNV)
			pglEndOcclusionQueryNV();
	}

	void QglGetQueryiv(GLenum target, GLenum pname, GLint* params)
	{
		if (pglGetQueryivARB)
			pglGetQueryivARB(target, pname, params);
	}

	void QglGetQueryObjectiv(GLuint id, GLenum pname, GLint* params)
	{
		if (pglGetQueryObjectivARB)
			pglGetQueryObjectivARB(id, pname, params);
		else if (pglGetOcclusionQueryivNV)
			pglGetOcclusionQueryivNV(id, pname, params);
	}

	void QglGetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params)
	{
		if (pglGetQueryObjectuivARB)
			pglGetQueryObjectuivARB(id, pname, params);
		else if (pglGetOcclusionQueryuivNV)
			pglGetOcclusionQueryuivNV(id, pname, params);
	}

	// 기타
	void QglSwapInterval(int interval)
	{
#if _SB_WINDOWS_
#ifdef WGL_EXT_swap_control
		if (pwglSwapIntervalEXT)
			pwglSwapIntervalEXT(interval);
#endif
#endif
		// 나머지는 만들어야 됨
	}

	// GL 테스트 함수
	void QglTestGlFunc()
	{
		k_mesgf("-- GL INFO FUNCTION : ENTER\n");

#define GTA(x) k_mesgf(K_STRING(x) ": %d\n", K_CONCAT(p,x) ? 1 : 0)
		// 텍스쳐
		GTA(glActiveTextureARB);
		GTA(glClientActiveTextureARB);
		GTA(glCompressedTexImage2D);
		GTA(glGenerateMipmap);
		GTA(glGenerateMipmapEXT);
		// 블렌드
		GTA(glBlendEquation);
		GTA(glBlendEquationEXT);
		GTA(glBlendFuncSeparate);
		GTA(glBlendFuncSeparateEXT);
		GTA(glEnableIndexedEXT);
		GTA(glDisableIndexedEXT);
		GTA(glColorMaskIndexedEXT);
		GTA(glBlendFunciARB);
		GTA(glBlendFuncIndexedAMD);
		GTA(glBlendEquationiARB);
		GTA(glBlendEquationIndexedAMD);
		// 레이아웃
		GTA(glEnableVertexAttribArray);
		GTA(glDisableVertexAttribArray);
		GTA(glSecondaryColorPointer);
		GTA(glVertexAttribPointer);
		// 프레임 버퍼 오브젝트
		GTA(glGenFramebuffers);
		GTA(glBindFramebuffer);
		GTA(glDeleteFramebuffers);
		GTA(glCheckFramebufferStatus);
		GTA(glFramebufferTexture1D);
		GTA(glFramebufferTexture2D);
		GTA(glFramebufferTexture3D);
		GTA(glGenRenderbuffers);
		GTA(glBindRenderbuffer);
		GTA(glDeleteRenderbuffers);
		GTA(glRenderbufferStorage);
		GTA(glFramebufferRenderbuffer);
		GTA(glGetRenderbufferParameteriv);
		GTA(glGetFramebufferAttachmentParameteriv);
		//
		GTA(glGenFramebuffersEXT);
		GTA(glBindFramebufferEXT);
		GTA(glDeleteFramebuffersEXT);
		GTA(glCheckFramebufferStatusEXT);
		GTA(glFramebufferTexture1DEXT);
		GTA(glFramebufferTexture2DEXT);
		GTA(glFramebufferTexture3DEXT);
		GTA(glGenRenderbuffersEXT);
		GTA(glBindRenderbufferEXT);
		GTA(glDeleteRenderbuffersEXT);
		GTA(glRenderbufferStorageEXT);
		GTA(glFramebufferRenderbufferEXT);
		GTA(glGetRenderbufferParameterivEXT);
		GTA(glGetFramebufferAttachmentParameterivEXT);
		// 프로그램과 세이더
		GTA(glCreateProgram);
		GTA(glDeleteProgram);
		GTA(glAttachShader);
		GTA(glDetachShader);
		GTA(glGetAttachedShaders);
		GTA(glGetProgramiv);
		GTA(glGetProgramInfoLog);
		GTA(glGetActiveAttrib);
		GTA(glGetActiveUniform);
		GTA(glGetAttribLocation);
		GTA(glGetUniformLocation);
		GTA(glCreateShader);
		GTA(glShaderSource);
		GTA(glCompileShader);
		GTA(glLinkProgram);
		GTA(glUseProgram);
		GTA(glDeleteShader);
		GTA(glGetShaderiv);
		GTA(glGetShaderInfoLog);
		GTA(glUniform1fvARB);
		GTA(glUniform2fvARB);
		GTA(glUniform3fvARB);
		GTA(glUniform4fvARB);
		GTA(glUniform1ivARB);
		GTA(glUniform2ivARB);
		GTA(glUniform3ivARB);
		GTA(glUniform4ivARB);
		GTA(glUniformMatrix2fvARB);
		GTA(glUniformMatrix3fvARB);
		GTA(glUniformMatrix4fvARB);
		GTA(glProgramParameteriARB);
		GTA(glProgramParameteriEXT);
		// 버퍼
		GTA(glGenBuffersARB);
		GTA(glBindBufferARB);
		GTA(glDeleteBuffersARB);
		GTA(glBufferDataARB);
		GTA(glBufferSubDataARB);
		GTA(glGetBufferSubDataARB);
		GTA(glMapBufferARB);
		GTA(glUnmapBufferARB);
		GTA(glIsBufferARB);
		GTA(glDrawBuffers);
		GTA(glDrawBuffersARB);
		GTA(glDrawBuffersATI);
		GTA(glProvokingVertexARB);
		GTA(glProvokingVertexEXT);
		// 포인트
		GTA(glPointParameterfARB);
		GTA(glPointParameterfvARB);
		// 스텐실
		GTA(glStencilFuncSeparate);
		GTA(glStencilFuncSeparateATI);
		GTA(glStencilOpSeparate);
		GTA(glStencilOpSeparateATI);
		GTA(glActiveStencilFaceEXT);
		// 폐쇄 질의 = 오클루젼
		GTA(glGenQueriesARB);
		GTA(glDeleteQueriesARB);
		GTA(glIsQueryARB);
		GTA(glBeginQueryARB);
		GTA(glEndQueryARB);
		GTA(glGetQueryivARB);
		GTA(glGetQueryObjectivARB);
		GTA(glGetQueryObjectuivARB);
		//
		GTA(glGenOcclusionQueriesNV);
		GTA(glDeleteOcclusionQueriesNV);
		GTA(glIsOcclusionQueryNV);
		GTA(glBeginOcclusionQueryNV);
		GTA(glEndOcclusionQueryNV);
		GTA(glGetOcclusionQueryivNV);
		GTA(glGetOcclusionQueryuivNV);
		// 수직 동기화
#if defined(WGL_EXT_swap_control) && !_QG_USE_SDL
		GTA(wglSwapIntervalEXT);
#endif
#if defined(GLX_SGI_swap_control) && !_QG_USE_SDL
		GTA(pglxSwapIntervalSGI);
#endif
#if defined(GLX_EXT_swap_control) && !_QG_USE_SDL
		GTA(pglxSwapIntervalEXT);
#endif
#if defined(GLX_MESA_swap_control) && !_QG_USE_SDL
		GTA(pglxSwapIntervalMESA);
#endif
#undef GTA

		k_mesgf("-- GL INFO FUNCTION : LEAVE\n");
	}

	// GL 전용 확장 능력 분석
	static void ParseExtension(const char* extstr)
	{
		k_return_if_fail(extstr);

		static const char* s_fs[] =
		{
			"GL_ARB_provoking_vertex",
			"GL_EXT_provoking_vertex",
			"GL_EXT_draw_buffers2",
			"GL_ARB_draw_buffers_blend",
			"GL_AMD_draw_buffers_blend",
			"GL_EXT_separate_specular_color",
			"GL_EXT_blend_subtract",
			"GL_EXT_blend_logic_op",
			"GL_NVX_gpu_memory_info",
			"GL_ATI_meminfo",
			"GL_ARB_multitexture",
			"GL_ARB_texture_compression",
			"GL_ARB_vertex_shader",
			"GL_EXT_texture_lod_bias",
			"GL_ARB_draw_buffers",
			"GL_ATI_draw_buffers",
			"GL_ARB_shading_language_100",
			"GL_ARB_occlusion_query",
			"GL_NV_occlusion_query",
			"GL_AMD_blend_minmax_factor",
			"GL_EXT_clip_volume_hint",
			"GL_ARB_texture_env_combine",
			"GL_EXT_texture_env_combine",
			"GL_EXT_texture_filter_anisotropic",
			"GL_MESA_pack_invert",
			"GL_ARB_texture_non_power_of_two",
			"GL_EXT_packed_depth_stencil",
		};

		static_assert(K_COUNTOF(s_fs) == QGLX_MAX_VALUE, "invalid QGLX count!");

		ksize_t i, z, len = k_strlen(extstr);
		char* psz = (char*)alloca(len + 1);
		char* prs;

		for (prs = psz, i = 0; i < len; i++)
		{
			psz[i] = extstr[i];

			if (psz[i] != ' ')
				continue;

			psz[i] = '\0';

			for (z = 0; z < K_COUNTOF(s_fs); z++)
			{
				if (k_streqv(prs, s_fs[z]))
				{
					GLCS[z] = true;
					break;
				}
			}

			prs = prs + k_strlen(prs) + 1;
		}
	}

	// 확장 기능 처리, 코드 참조: Irrlicht, OGRE
	void InitializeExtension()
	{
		// 여러번 할 필요 없다
		static bool sIsInit = false;

		k_return_if_ok(sIsInit);

		sIsInit = true;

		// 플랫폼에 따른 확장 기능 가져오기
#if _SB_WINDOWS_ && !_QG_USE_SDL
#	define GPA(x)        wglGetProcAddress(x)
#elif _QG_USE_SDL
#	define GPA(x)        SDL_GL_GetProcAddress(x)
#elif _SB_LINUX_ || _SB_BSD_
		// 으앙!!!
#error please fix me!!!
#else
#	define GPA(x)		glXGetProcAddressARB(x)
#endif

		// 텍스쳐
		pglActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)GPA("glActiveTextureARB");
		pglClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)GPA("glClientActiveTextureARB");
		pglCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)GPA("glCompressedTexImage2D");
		pglGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)GPA("glGenerateMipmap");
		pglGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)GPA("glGenerateMipmapEXT");
		// 블렌드
		pglBlendEquation = (PFNGLBLENDEQUATIONPROC)GPA("glBlendEquation");
		pglBlendEquationEXT = (PFNGLBLENDEQUATIONEXTPROC)GPA("glBlendEquationEXT");
		pglBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)GPA("glBlendFuncSeparate");
		pglBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC)GPA("glBlendFuncSeparateEXT");
		pglEnableIndexedEXT = (PFNGLENABLEINDEXEDEXTPROC)GPA("glEnableIndexedEXT");
		pglDisableIndexedEXT = (PFNGLDISABLEINDEXEDEXTPROC)GPA("glDisableIndexedEXT");
		pglColorMaskIndexedEXT = (PFNGLCOLORMASKINDEXEDEXTPROC)GPA("glColorMaskIndexedEXT");
		pglBlendFunciARB = (PFNGLBLENDFUNCIPROC)GPA("glBlendFunciARB");
		pglBlendFuncIndexedAMD = (PFNGLBLENDFUNCINDEXEDAMDPROC)GPA("glBlendFuncIndexedAMD");
		pglBlendEquationiARB = (PFNGLBLENDEQUATIONIPROC)GPA("glBlendEquationiARB");
		pglBlendEquationIndexedAMD = (PFNGLBLENDEQUATIONINDEXEDAMDPROC)GPA("glBlendEquationIndexedAMD");
		// 레이아웃
		pglEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)GPA("glEnableVertexAttribArray");
		pglDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)GPA("glDisableVertexAttribArray");
		pglSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)GPA("glSecondaryColorPointer");
		pglVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)GPA("glVertexAttribPointer");
		// 프레임 버퍼 오브젝트
		pglGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)GPA("glGenFramebuffers");
		pglBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)GPA("glBindFramebuffer");
		pglDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)GPA("glDeleteFramebuffers");
		pglCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)GPA("glCheckFramebufferStatus");
		pglFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)GPA("glFramebufferTexture1D");
		pglFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)GPA("glFramebufferTexture2D");
		pglFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)GPA("glFramebufferTexture3D");
		pglGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)GPA("glGenRenderbuffers");
		pglBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)GPA("glBindRenderbuffer");
		pglDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)GPA("glDeleteRenderbuffers");
		pglRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)GPA("glRenderbufferStorage");
		pglFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)GPA("glFramebufferRenderbuffer");
		pglGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)GPA("glGetRenderbufferParameteriv");
		pglGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)GPA("glGetFramebufferAttachmentParameteriv");
		//
		pglGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)GPA("glGenFramebuffersEXT");
		pglBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)GPA("glBindFramebufferEXT");
		pglDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)GPA("glDeleteFramebuffersEXT");
		pglCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)GPA("glCheckFramebufferStatusEXT");
		pglFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)GPA("glFramebufferTexture1DEXT");
		pglFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)GPA("glFramebufferTexture2DEXT");
		pglFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)GPA("glFramebufferTexture3DEXT");
		pglGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)GPA("glGenRenderbuffersEXT");
		pglBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)GPA("glBindRenderbufferEXT");
		pglDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)GPA("glDeleteRenderbuffersEXT");
		pglRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)GPA("glRenderbufferStorageEXT");
		pglFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)GPA("glFramebufferRenderbufferEXT");
		pglGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)GPA("glGetRenderbufferParameterivEXT");
		pglGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)GPA("glGetFramebufferAttachmentParameterivEXT");
		// 프로그램과 세이더
		pglCreateProgram = (PFNGLCREATEPROGRAMPROC)GPA("glCreateProgram");
		pglDeleteProgram = (PFNGLDELETEPROGRAMPROC)GPA("glDeleteProgram");
		pglAttachShader = (PFNGLATTACHSHADERPROC)GPA("glAttachShader");
		pglDetachShader = (PFNGLDETACHSHADERPROC)GPA("glDetachShader");
		pglGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)GPA("glGetAttachedShaders");
		pglGetProgramiv = (PFNGLGETPROGRAMIVPROC)GPA("glGetProgramiv");
		pglGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)GPA("glGetProgramInfoLog");
		pglGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)GPA("glGetActiveAttrib");
		pglGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)GPA("glGetActiveUniform");
		pglGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)GPA("glGetAttribLocation");
		pglGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)GPA("glGetUniformLocation");
		pglCreateShader = (PFNGLCREATESHADERPROC)GPA("glCreateShader");
		pglShaderSource = (PFNGLSHADERSOURCEPROC)GPA("glShaderSource");
		pglCompileShader = (PFNGLCOMPILESHADERPROC)GPA("glCompileShader");
		pglLinkProgram = (PFNGLLINKPROGRAMPROC)GPA("glLinkProgram");
		pglUseProgram = (PFNGLUSEPROGRAMPROC)GPA("glUseProgram");
		pglDeleteShader = (PFNGLDELETESHADERPROC)GPA("glDeleteShader");
		pglGetShaderiv = (PFNGLGETSHADERIVPROC)GPA("glGetShaderiv");
		pglGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)GPA("glGetShaderInfoLog");
		pglUniform1fvARB = (PFNGLUNIFORM1FVARBPROC)GPA("glUniform1fvARB");
		pglUniform2fvARB = (PFNGLUNIFORM2FVARBPROC)GPA("glUniform2fvARB");
		pglUniform3fvARB = (PFNGLUNIFORM3FVARBPROC)GPA("glUniform3fvARB");
		pglUniform4fvARB = (PFNGLUNIFORM4FVARBPROC)GPA("glUniform4fvARB");
		pglUniform1ivARB = (PFNGLUNIFORM1IVARBPROC)GPA("glUniform1ivARB");
		pglUniform2ivARB = (PFNGLUNIFORM2IVARBPROC)GPA("glUniform2ivARB");
		pglUniform3ivARB = (PFNGLUNIFORM3IVARBPROC)GPA("glUniform3ivARB");
		pglUniform4ivARB = (PFNGLUNIFORM4IVARBPROC)GPA("glUniform4ivARB");
		pglUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC)GPA("glUniformMatrix2fvARB");
		pglUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC)GPA("glUniformMatrix3fvARB");
		pglUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC)GPA("glUniformMatrix4fvARB");
		pglProgramParameteriARB = (PFNGLPROGRAMPARAMETERIARBPROC)GPA("glProgramParameteriARB");
		pglProgramParameteriEXT = (PFNGLPROGRAMPARAMETERIEXTPROC)GPA("glProgramParameteriEXT");
		// 버퍼
		pglGenBuffersARB = (PFNGLGENBUFFERSARBPROC)GPA("glGenBuffersARB");
		pglBindBufferARB = (PFNGLBINDBUFFERARBPROC)GPA("glBindBufferARB");
		pglDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)GPA("glDeleteBuffersARB");
		pglBufferDataARB = (PFNGLBUFFERDATAARBPROC)GPA("glBufferDataARB");
		pglBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)GPA("glBufferSubDataARB");
		pglGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)GPA("glGetBufferSubDataARB");
		pglMapBufferARB = (PFNGLMAPBUFFERARBPROC)GPA("glMapBufferARB");
		pglUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)GPA("glUnmapBufferARB");
		pglIsBufferARB = (PFNGLISBUFFERARBPROC)GPA("glIsBufferARB");
		pglDrawBuffers = (PFNGLDRAWBUFFERSPROC)GPA("glDrawBuffers");
		pglDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC)GPA("glDrawBuffersARB");
		pglDrawBuffersATI = (PFNGLDRAWBUFFERSATIPROC)GPA("glDrawBuffersATI");
		pglProvokingVertexARB = (PFNGLPROVOKINGVERTEXPROC)GPA("glProvokingVertex");
		pglProvokingVertexEXT = (PFNGLPROVOKINGVERTEXEXTPROC)GPA("glProvokingVertexEXT");
		// 포인트
		pglPointParameterfARB = (PFNGLPOINTPARAMETERFARBPROC)GPA("glPointParameterfARB");
		pglPointParameterfvARB = (PFNGLPOINTPARAMETERFVARBPROC)GPA("glPointParameterfvARB");
		// 스텐실
		pglStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)GPA("glStencilFuncSeparate");
		pglStencilFuncSeparateATI = (PFNGLSTENCILFUNCSEPARATEATIPROC)GPA("glStencilFuncSeparateATI");
		pglStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)GPA("glStencilOpSeparate");
		pglStencilOpSeparateATI = (PFNGLSTENCILOPSEPARATEATIPROC)GPA("glStencilOpSeparateATI");
		pglActiveStencilFaceEXT = (PFNGLACTIVESTENCILFACEEXTPROC)GPA("glActiveStencilFaceEXT");
		// 폐쇄 질의 = 오클루젼
		pglGenQueriesARB = (PFNGLGENQUERIESARBPROC)GPA("glGenQueriesARB");
		pglDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC)GPA("glDeleteQueriesARB");
		pglIsQueryARB = (PFNGLISQUERYARBPROC)GPA("glIsQueryARB");
		pglBeginQueryARB = (PFNGLBEGINQUERYARBPROC)GPA("glBeginQueryARB");
		pglEndQueryARB = (PFNGLENDQUERYARBPROC)GPA("glEndQueryARB");
		pglGetQueryivARB = (PFNGLGETQUERYIVARBPROC)GPA("glGetQueryivARB");
		pglGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC)GPA("glGetQueryObjectivARB");
		pglGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC)GPA("glGetQueryObjectuivARB");
		//
		pglGenOcclusionQueriesNV = (PFNGLGENOCCLUSIONQUERIESNVPROC)GPA("glGenOcclusionQueriesNV");
		pglDeleteOcclusionQueriesNV = (PFNGLDELETEOCCLUSIONQUERIESNVPROC)GPA("glDeleteOcclusionQueriesNV");
		pglIsOcclusionQueryNV = (PFNGLISOCCLUSIONQUERYNVPROC)GPA("glIsOcclusionQueryNV");
		pglBeginOcclusionQueryNV = (PFNGLBEGINOCCLUSIONQUERYNVPROC)GPA("glBeginOcclusionQueryNV");
		pglEndOcclusionQueryNV = (PFNGLENDOCCLUSIONQUERYNVPROC)GPA("glEndOcclusionQueryNV");
		pglGetOcclusionQueryivNV = (PFNGLGETOCCLUSIONQUERYIVNVPROC)GPA("glGetOcclusionQueryivNV");
		pglGetOcclusionQueryuivNV = (PFNGLGETOCCLUSIONQUERYUIVNVPROC)GPA("glGetOcclusionQueryuivNV");
		// 수직 동기화
#if defined(WGL_EXT_swap_control) && !_QG_USE_SDL
		pwglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)GPA("wglSwapIntervalEXT");
#endif
#if defined(GLX_SGI_swap_control) && !_QG_USE_SDL
		pglxSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)IRR_OGL_LOAD_EXTENSION("glXSwapIntervalSGI");
#endif
#if defined(GLX_EXT_swap_control) && !_QG_USE_SDL
		pglxSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)IRR_OGL_LOAD_EXTENSION("glXSwapIntervalEXT");
#endif
#if defined(GLX_MESA_swap_control) && !_QG_USE_SDL
		pglxSwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)IRR_OGL_LOAD_EXTENSION("glXSwapIntervalMESA");
#endif
#undef GPA

		// 확장 문자열로 능력 분석
		const char* extstr = (const char*)glGetString(GL_EXTENSIONS);
		ParseExtension(extstr);
	}

	// 기능 점검
	void InitializeCaps(qgDevCaps& pc, bool usestencil)
	{
		kany a;

		// 버전
		a.f = k_atof((const char*)glGetString(GL_VERSION));
		pc.version = (kushort)(k_floor(a.f) * 100.0f + k_ceil(k_fract(a.f) * 10.0f));

		// 벤더
		k_strncpy(pc.renderer, (const char*)glGetString(GL_RENDERER), 64);
		k_strncpy(pc.vendor, (const char*)glGetString(GL_VENDOR), 64);

		// 스텐실
		pc.supp_stencil = usestencil;

		// 멀티텍스쳐
		pc.supp_multi_texture = GLCS[QGLX_ARB_MULTITEXTURE];

		// 텍스쳐 압축
		pc.supp_compressed_texture = GLCS[QGLX_ARB_TEXTURE_COMPRESSION];

		// 세이더
		pc.supp_shader = GLCS[QGLX_ARB_VERTEX_SHADER];

		// 텍스쳐 2의 승수 아닌거 지원
		pc.supp_texture_npo2 = GLCS[QGLX_ARB_TEXTURE_NON_POWER_OF_TWO];

		// 텍슷 개수
		if (!pc.supp_multi_texture)
			pc.max_texture_count = 1;
#if defined(GL_ARB_multitexture) || defined(GL_VERSION_1_3)
		else if (pc.version > 102 || pc.supp_multi_texture)
		{
			a.i = 0;
#if defined(GL_MAX_TEXTURE_UNITS)
			glGetIntegerv(GL_MAX_TEXTURE_UNITS, &a.i);
#elif defined(GL_MAX_TEXTURE_UNITS_ARB)
			glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &a.i);
#endif
			pc.max_texture_count = (kbyte)K_MIN(a.i, QGSGTEX_MAX_VALUE);
		}
#endif

#if defined(GL_ARB_vertex_shader) || defined(GL_VERSION_2_0)
		if (pc.version >= 200 || pc.supp_shader)
		{
			a.i = 0;
#if defined(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)
			glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &a.i);
#elif defined(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB)
			glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, &a.i);
#endif
			a.i = K_MAX(pc.max_texture_count, (kbyte)a.i);
			pc.max_texture_count = (kbyte)K_MIN(a.i, QGSGTEX_MAX_VALUE);
		}
#endif

		// 라이트
		//glGetIntegerv(GL_MAX_LIGHTS, &a.i);
		//pc.max_lights = (kbyte)n;

		// 인덱스 개수
#ifdef GL_VERSION_1_2
		glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &a.i);
		pc.max_indices_count = a.i;
#endif

		// 텍스쳐 크기
		glGetIntegerv(GL_MAX_TEXTURE_SIZE, &a.i);
		pc.max_texture_dimension = (kuint)a.i;

		// 지오메트리 세이더 정점
#if defined(GL_ARB_geometry_shader4) || defined(GL_EXT_geometry_shader4) || defined(GL_NV_geometry_shader4)
		glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, &a.i);
#elif defined(GL_NV_geometry_program4)
		QglGetProgramiv(GEOMETRY_PROGRAM_NV, GL_MAX_PROGRAM_OUTPUT_VERTICES_NV, &a.i);
#else
		a.i = 0;
#endif
		pc.max_gs_vertices_count = (kuint)a.i;

		// LOD Bias
#ifdef GL_EXT_texture_lod_bias
		if (GLCS[QGLX_EXT_TEXTURE_LOD_BIAS])
			glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS_EXT, &pc.max_texture_LOD_bias);
#endif

		// user clip planes
		glGetIntegerv(GL_MAX_CLIP_PLANES, &a.i);
		pc.max_clip_planes = (kbyte)a.i;

		// max aux
		//glGetIntegerv(GL_AUX_BUFFERS, &a.i);
		//pc.max_aux_bufs = (kbyte)a.i;

		// 오프
#ifdef GL_ARB_draw_buffers
		if (GLCS[QGLX_ARB_DRAW_BUFFERS])
		{
			glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &a.i);
			pc.max_offtex_count = (kbyte)a.i;
		}
#endif
#ifdef GL_ATI_draw_buffers
#ifdef GL_ARB_draw_buffers
		else
#endif
		{
			if (GLCS[QGLX_ATI_DRAW_BUFFERS])
			{
				glGetIntegerv(GL_MAX_DRAW_BUFFERS_ATI, &a.i);
				pc.max_offtex_count = (kbyte)a.i;
			}
		}
#endif

		// dim
		glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, pc.dim_alias_line);
		glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pc.dim_alias_point);
		glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, pc.dim_smt_line);
		glGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, pc.dim_smt_point);

		// 세이더 버전
#if defined(GL_ARB_shading_language_100) || defined (GL_VERSION_2_0)
		if (GLCS[QGLX_ARB_SHADING_LANGUAGE_100] || pc.version >= 200)
		{
			// 여기는 무조건 지원해야함
			glGetError();

#ifdef GL_SHADING_LANGUAGE_VERSION
			a.cp = glGetString(GL_SHADING_LANGUAGE_VERSION);
#else
			a.cp = glGetString(GL_SHADING_LANGUAGE_VERSION_ARB);
#endif

			if (glGetError() == GL_INVALID_ENUM)
				pc.version_shader = 100;
			else
			{
				a.f = k_atof((const char*)a.cp);
				pc.version_shader = (kushort)(k_floor(a.f) * 100.0f + k_ceil(k_fract(a.f) * 10.0f));
			}
		}
#endif

		// 오클루전 쿼리
#ifdef GL_ARB_occlusion_query
		if (GLCS[QGLX_ARB_OCCLUSION_QUERY])
		{
			QglGetQueryiv(GL_SAMPLES_PASSED_ARB, GL_QUERY_COUNTER_BITS_ARB, &a.i);
			pc.supp_occlusion = a.i > 0;
		}
#ifdef GL_NV_occlusion_query
		else
#endif
#endif
#ifdef GL_NV_occlusion_query
		{
			if (GLCS[QGLX_NV_OCCLUSION_QUERY])
			{
				glGetIntegerv(GL_PIXEL_COUNTER_BITS_NV, &a.i);
				pc.supp_occlusion = a.i > 0;
			}
		}
#endif
	}
}

#endif	// _QG_USE_GL
